#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright (C) 1994  Ling Li
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import os, os.path, string, sys, time, re, stat

import gobject, gtk, gtk.gdk
from gtk import *

from coralftp_globals import *
from configuration import config_value
from filetype import *
from general_input import *
from transfer_view import *
from utils import *

class LocalFileInfo:
    __name = None
    __stat = None

    def __init__(self, filepath):
        self.__name = os.path.basename(filepath)
        self.__stat = os.stat(filepath)
        return

    def __getattr__(self, name):
        if name == 'name':
            return self.__name
        elif name == 'size':
            return self.__stat[stat.ST_SIZE]
        elif name == 'mtime':
            return self.__stat[stat.ST_MTIME]
        elif name == 'stat':
            return self.__stat
        else:
            raise AttributeError, name

    def is_dir(self):
        return stat.S_ISDIR(self.__stat[stat.ST_MODE])

    def is_regular(self):
        return stat.S_ISREG(self.__stat[stat.ST_MODE])

    def is_link(self):
        return stat.S_ISLNK(self.__stat[stat.ST_MODE])

class LocalView:

    COL_ICON = 0
    COL_FILENAME = 1
    COL_FILESIZE = 2
    COL_FILETYPE = 3
    COL_FILEMTIME = 4
    COL_INFO = 5

    # this is used to store how many rows are selected in file list view
    __selected_count = 0    
    __selections = []
    __change_selection_now = False

    __change_sort_menu_item = True

    __use_custom_file_listing_font = False
    __file_listing_font = None
    __text_renderers = []
    __show_hidden = False
    
    def __init__(self, main_window):

        ACTIONS = {
            'updir' : { 'sensitive' : True,
                        'update' : self.on_updir_action_update,
                        'execute' : self.on_updir_action_execute },
            'transfer' : { 'sensitive' : False,
                           'update' : self.on_transfer_queue_action_update,
                           'execute' : self.on_transfer_action_execute },
            'queue' : { 'sensitive' : False,
                        'update' : self.on_transfer_queue_action_update,
                        'execute' : self.on_queue_action_execute },
            'transfer_as' : { 'sensitive' : False,
                              'update' : self.on_transfer_queue_as_action_update,
                              'execute' : self.on_transfer_as_action_execute },
            'queue_as' : { 'sensitive' : False,
                           'update' : self.on_transfer_queue_as_action_update,
                           'execute' : self.on_queue_as_action_execute },
            'delete' : { 'sensitive' : False,
                         'update' : self.on_delete_action_update,
                         'execute' : self.on_delete_action_execute },
            'rename' : { 'sensitive' : False,
                         'update' : self.on_rename_action_update,
                         'execute' : self.on_rename_action_execute },
            'mkdir' : { 'sensitive' : True,
                        'execute' : self.on_mkdir_action_execute },
            'chdir' : { 'sensitive' : True,
                        'execute' : self.on_chdir_action_execute },
            'refresh' : { 'sensitive' : True,
                          'execute' : self.on_refresh_action_execute },
            'sort' : { 'sensitive' : True,
                       'execute' : self.on_sort_action_execute },
            'open' : { 'sensitive' : True,
                       'update' : self.on_open_action_update,
                       'execute' : self.on_open_action_execute },
            'save_path' : { 'sensitive' : False },
            'property' : { 'sensitive' : False },
            'show_hidden' : { 'sensitive' : True,
                              'execute' : self.on_show_hidden_execute },
            }

        WIDGET_ACTIONS = {
            'btn_local_updir' : 'updir',
            'tbtn_local_refresh' : 'refresh',
            }

        MENU_ACTIONS = {
            'mi_local_transfer' : 'transfer',
            'mi_local_queue' : 'queue',
            'mi_local_transfer_as' : 'transfer_as',
            'mi_local_queue_as' : 'queue_as',
            'mi_local_open' : 'open',
            'mi_local_delete' : 'delete',
            'mi_local_rename' : 'rename',
            'mi_local_properties' : 'property',
            'mi_local_save_path' : 'save_path',
            'mi_local_make_folder' : 'mkdir',
            'mi_local_change_folder' : 'chdir',
            'mi_local_refresh' : 'refresh',
            'mi_local_arr_by_name' : 'sort',
            'mi_local_arr_by_type' : 'sort',
            'mi_local_arr_by_size' : 'sort',
            'mi_local_arr_by_date' : 'sort',
            'mi_local_arr_ascending' : 'sort',
            'mi_local_arr_descending' : 'sort',
            'mi_local_show_hidden' : 'show_hidden',
            }
        
        self.__main_window = main_window
        self.__xml = main_window.xml
        self.__widget = self.__xml.get_widget('local_view')
        self.__config = self.__main_window.config
        self.__current_path = os.getcwdu()
        self.actions = ActionList(ACTIONS)

        self.__menu_xml = get_glade_xml('local_file_list_menu')
        self.__menu = self.__menu_xml.get_widget('local_file_list_menu')

        # prepare interface
        #self.__widget.connect('show', gobject.idle_add, self.refresh)

        # file list
        self.__model = ListStore(gtk.gdk.Pixbuf,
                                 gobject.TYPE_STRING,
                                 gobject.TYPE_STRING,
                                 gobject.TYPE_STRING,
                                 gobject.TYPE_STRING,
                                 gobject.TYPE_PYOBJECT)
        self.__model.set_sort_func(LocalView.COL_ICON, self.filelist_sort)
        self.__model.set_sort_func(LocalView.COL_FILENAME,
                                   self.filelist_sort)
        self.__model.set_sort_func(LocalView.COL_FILESIZE,
                                   self.filelist_sort)
        self.__model.set_sort_func(LocalView.COL_FILETYPE,
                                   self.filelist_sort)
        self.__model.set_sort_func(LocalView.COL_FILEMTIME,
                                   self.filelist_sort)
        self.__list = self.__xml.get_widget('tv_local_file_list')
        self.__list.set_model(self.__model)
        self.__list.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.__list.get_selection().set_select_function(self.__select_func)

        column = TreeViewColumn(_("Name"))
        renderer = CellRendererPixbuf()
        column.pack_start(renderer, expand=False)
        column.add_attribute(renderer, 'pixbuf', LocalView.COL_ICON)
        renderer = CellRendererText()
        self.__text_renderers.append(renderer)
        column.pack_start(renderer, expand=True)
        column.add_attribute(renderer, 'text', LocalView.COL_FILENAME)
        column.set_sort_column_id(LocalView.COL_FILENAME)
        column.set_resizable(True)
        self.__list.append_column(column)

        renderer = CellRendererText()
        self.__text_renderers.append(renderer)
        renderer.set_property('xalign', 1)
        column = TreeViewColumn(_("Size"), renderer,
                                text=LocalView.COL_FILESIZE)
        column.set_resizable(True)
        column.set_sort_column_id(LocalView.COL_FILESIZE)
        self.__list.append_column(column)

        renderer = CellRendererText()
        self.__text_renderers.append(renderer)
        column = TreeViewColumn(_("Type"), renderer,
                                text=LocalView.COL_FILETYPE)
        column.set_resizable(True)
        column.set_sort_column_id(LocalView.COL_FILETYPE)
        self.__list.append_column(column)

        renderer = CellRendererText()
        self.__text_renderers.append(renderer)
        column = TreeViewColumn(_("Modified"), renderer,
                                text=LocalView.COL_FILEMTIME)
        column.set_sort_column_id(LocalView.COL_FILEMTIME)
        column.set_resizable(True)
        self.__list.append_column(column)

        self.__cmb_dir = self.__xml.get_widget('cmb_local_dir')
        self.__cmb_dir.set_model(ListStore(gobject.TYPE_STRING))
        cell = gtk.CellRendererText()
        self.__cmb_dir.pack_start(cell, True)
        self.__cmb_dir.add_attribute(cell, 'text', 0)
        self.__cmb_dir.connect('changed', self.on_cmb_dir_changed)
        self.__cmb_dir.child.connect('activate',
                                     self.on_local_dir_entry_activate)
        self.__status1 = self.__xml.get_widget('label_local_status1')
        self.__status2 = self.__xml.get_widget('label_local_status2')
        self.active_indicator = self.__xml.get_widget('eb_local')

        # set sort column & order
        self.__model.connect('sort-column-changed',
                             self.on_list_sort_column_changed)
        value = config_value(self.__config, 'display', 'local_sort_by')
        if value == 0:
            sort_column = LocalView.COL_FILENAME
        elif value == 1:
            sort_column = LocalView.COL_FILETYPE
        elif value == 2:
            sort_column = LocalView.COL_FILESIZE
        elif value == 3:
            sort_column = LocalView.COL_FILEMTIME
        else:
            raise ValueError
        value = config_value(self.__config, 'display', 'local_order')
        sort_order = value
        self.__model.set_sort_column_id(sort_column, sort_order)

        # setup fonts
        self.__use_custom_file_listing_font = config_value(
            self.__config, 'display', 'use_custom_file_listing_font')
        self.__file_listing_font = config_value(
            self.__config, 'display', 'file_listing_font')
        self.__change_font()
        self.__config.notify_add(
            'display', 'use_custom_file_listing_font',
            self.on_use_custom_file_listing_font_change)
        self.__config.notify_add(
            'display', 'file_listing_font',
            self.on_file_listing_font_change)

        # setup column resize
        self.__config.notify_add(
            'display', 'auto_size_file_list_columns',
            self.on_auto_size_file_list_columns_change)
        auto_size_file_list_columns = config_value(
            self.__config, 'display', 'auto_size_file_list_columns')
        for column in self.__list.get_columns():
            if auto_size_file_list_columns:
                column.set_sizing(TREE_VIEW_COLUMN_AUTOSIZE)
            else:
                column.set_sizing(TREE_VIEW_COLUMN_GROW_ONLY)

        # rules hint
        self.__list.set_property('rules-hint',
                                 config_value(self.__config, 'display',
                                              'rules_hint'))
        self.__config.notify_add(
            'display', 'rules_hint',
            lambda config, id, value, *args: \
            self.__list.set_property('rules-hint', value.get_bool()))

        self.__frame4 = self.__xml.get_widget('frame_local_4')
        self.__frame5 = self.__xml.get_widget('frame_local_5')
        self.active_indicator = self.__xml.get_widget('eb_local')
        self.__status1 = self.__xml.get_widget('label_local_status1')
        self.__status2 = self.__xml.get_widget('label_local_status2')

        # connect some signals with handler
        self.__list.connect("button-press-event",
                            self.on_list_button_press)
        self.__list.connect("button-release-event",
                            self.on_list_button_release)

        # connect widgets with actions
        for widget_name, action_name in WIDGET_ACTIONS.items():
            widget = self.__xml.get_widget(widget_name)
            self.actions[action_name].attach(widget)

        # connect menu items with actions
        for widget_name, action_name in MENU_ACTIONS.items():
            widget = self.__menu_xml.get_widget(widget_name)
            self.actions[action_name].attach(widget)

        # set current path
        default_download_path = config_value(
            self.__config, 'general', 'default_download_path')
        if default_download_path:
            default_download_path = utf8_to_unicode(default_download_path)
        if default_download_path:
            default_download_path = os.path.expanduser(default_download_path)
        if default_download_path and os.path.isdir(default_download_path):
            gobject.idle_add(self.set_path, default_download_path)
        else:
            gobject.idle_add(self.set_path, os.getcwd())
        return

    def __getattr__(self, name):
        if name == 'model':
            return self.__model
        elif name == 'current_path':
            return self.__current_path
        elif name == 'main_window':
            return self.__main_window
        else:
            raise AttributeError, name

    def __count_selection(self, treemodel, path, iter, data):
        info = self.__model.get_value(iter, LocalView.COL_INFO)
        if info.name != '..':
            data.append(iter)
        return

    def __select_func(self, *args):
        return self.__change_selection_now

    def on_list_button_press(self, obj, event):
        """In this function, double click of left button is processed.
        The basic action is:
        If only one item is selected and it is a folder, enter that
        directory.
        If multiple items are selected and another view is remote
        view, transfer them."""

        if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
            self.__change_selection_now = True
        if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
            self.__change_selection_now = False

        self.__main_window.set_active_view(self)
        
        selection = self.__list.get_selection()
        self.__selections = []
        selection.selected_foreach(self.__count_selection, self.__selections)
        self.__selected_count = len(self.__selections)
        self.__update_status1()
        
        if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:

            # if selection is parent directory
            if selection.count_selected_rows() == 1 and self.__selected_count == 0:
                file_path = os.path.dirname(self.__current_path)
                self.set_path(file_path)
            
            # if only one item is selected and it is a folder
            if self.__selected_count == 1:
                info = self.__model.get_value(self.__selections[0], LocalView.COL_INFO)
                file_path = os.path.join(self.__current_path, info.name)
                if os.path.isdir(file_path):
                    # for directory, enter it
                    self.set_path(file_path)
                else:
                    # the default action for double click is transfer
                    pass
        return

    def on_list_button_release(self, obj, event):
        """The right cilck is processed in this method. By default,
        a popup menu is showed."""
        
        selection = self.__list.get_selection()
        self.__selected_count = selection.count_selected_rows()
        self.__selections = []
        selection.selected_foreach(self.__count_selection, self.__selections)
        self.__update_status1()
        
        if event.button == 3:
            self.__menu.popup(None, None, None, 0, 0)
        return

    def on_cmb_dir_changed(self, obj, *args):
        iter = self.__cmb_dir.get_active_iter()
        if iter == None: return
        v = self.__cmb_dir.get_model().get_value(iter, 0)
        if v != self.__current_path:
            self.set_path(v)
        return
    
    def set_active_view(self, active=False):
        if active:
            self.active_indicator.set_name('active_view_indicator')
        else:
            self.active_indicator.set_name('')
        return

    def set_path(self, new_path):
        """Set the current directory of the view. After set, the view will be
        refreshed."""
        if isinstance(new_path, unicode):
            self.__current_path = new_path
        else:
            self.__current_path = utf8_to_unicode(new_path)
        self.__cmb_dir.child.set_text(self.__current_path)
        self.__status2.set_text(self.__current_path)
        self.refresh()
        # display status1
        self.__update_status1()
        
        model = self.__cmb_dir.get_model()
        iter = model.get_iter_first()
        found = False
        while iter != None:
            v = model.get_value(iter, 0)
            if v == new_path:
                found = True
                break
            iter = model.iter_next(iter)
        if not found:
            model.append((new_path,))
        return

    def __update_status1(self):
        display_file_size_as = config_value(self.__config, 'display',
                                            'display_file_size_as')
        if self.__folder_count > 1:
            text = _("%d Folders") % self.__folder_count
        else:
            text = _("%d Folder") % self.__folder_count
        if self.__file_count > 1:
            text = _("%s, %d Files") % (text, self.__file_count)
        else:
            text = _("%s, %d File") % (text, self.__file_count)
        total = self.__folder_count + self.__file_count
        text = _("%s, %d Total") % (text, total)
        if self.__selected_count != 0:
            size = 0
            for iter in self.__selections:
                info = self.__model.get_value(iter, LocalView.COL_INFO)
                if not info.is_dir():
                    size = size + info.size
            size = format_size(display_file_size_as, size)
            if size[-1] != 'B': size = size + _(" bytes")
            text = text + _(", %d Selected(%s)") % (self.__selected_count, size)
        else:
            iter = self.__model.get_iter_first()
            size = 0
            while iter:
                info = self.__model.get_value(iter, LocalView.COL_INFO)
                if not info.is_dir():
                    size = size + info.size
                iter = self.__model.iter_next(iter)
            size = format_size(display_file_size_as, size)
            text = text + '(%s)' % (size)
        self.__status1.set_text(text)
        return

    def refresh(self, in_thread = False):
        self.__folder_count = 0
        self.__file_count = 0
        self.__selected_count = 0
        self.__selections = []
        self.__model.clear()
        display_file_size_as = config_value(self.__config, 'display',
                                            'display_file_size_as')
        dir = ['..']
        dir.extend(os.listdir(self.__current_path))
        for filename in dir:
            if file.name == '.': continue
            
            if filename[0] == '.' and not self.__show_hidden: continue
            
            iter = self.__model.append()
            try:
                info = LocalFileInfo(
                    os.path.join(self.__current_path, filename))
            except OSError, e:
                self.__model.remove(iter)
                continue
            self.__model.set_value(iter, LocalView.COL_INFO, info)
            
            if info.name == '..':
                image = gdk.pixbuf_new_from_file(
                    os.path.join(coralftp_datadir, 'parent_dir.png'))
                self.__model.set_value(iter, LocalView.COL_ICON, image)
                self.__model.set_value(iter, LocalView.COL_FILENAME,
                                       _("Parent Directory"))
                continue

            self.__model.set_value(iter, LocalView.COL_FILENAME, info.name)
            if info.is_dir():
                self.__folder_count = self.__folder_count + 1
                self.__model.set_value(iter, LocalView.COL_FILETYPE,
                                       _("Folder"))
            elif info.is_regular():
                self.__file_count = self.__file_count + 1
                filetype = get_filetype(
                    os.path.join(self.__current_path, info.name))
                desc = filetype.description
                self.__model.set_value(iter, LocalView.COL_FILETYPE, desc)
                    
            self.__model.set_value(iter, LocalView.COL_FILESIZE,
                                   format_size(display_file_size_as,
                                               info.size))
            fmtime = locale_to_unicode(
                time.strftime('%F %r', time.gmtime(info.mtime)))
            self.__model.set_value(iter, LocalView.COL_FILEMTIME, fmtime)
            
            if info.is_dir():
                pixbuf = gdk.pixbuf_new_from_file(
                    os.path.join(coralftp_datadir, 'folder.png'))
                self.__model.set_value(iter, LocalView.COL_ICON, pixbuf)
        return

    def add_to_queue(self, treemodel, path, iter, data):
        if self.__main_window.mode == self.__main_window.MODE_FTP:
            direction = TransferView.DIRECTION_UP
            info = treemodel.get_value(iter, LocalView.COL_INFO)
            source = u'%s/%s' % (self.__cmb_dir.child.get_text(), info.name)
            remote_view = self.__main_window.remote_view
            if data == None:
                target = u'ftp://%s@%s%s/%s' \
                         % (remote_view.site_info['username'],
                            remote_view.site_info['server_addr'],
                            remote_view.current_path, info.name)
            else:
                target = u'ftp://%s@%s%s/%s' \
                         % (remote_view.site_info['username'],
                            remote_view.site_info['server_addr'],
                            remote_view.current_path, data)
            if info.is_dir():
                source = source + '/'
                target = target + '/'
            self.__main_window.transfer_view.add_to_queue(
                direction, source, target, info.size,
                None, remote_view.site_info)
        return

    def add_all_to_queue(self, trans_iter, target_path):
        """
        Add all the item in the list to the transfer queue.
        """
        tview = self.__main_window.transfer_view
        remote_view = self.__main_window.remote_view
        direction = TransferView.DIRECTION_UP
        iter = self.__model.get_iter_first()
        while iter:
            info = self.__model.get_value(iter, LocalView.COL_INFO)
            if info.name != '..':
                source = u'%s/%s' % (self.__cmb_dir.child.get_text(),
                                    info.name)
                target = u'%s%s' % (target_path, info.name)
                if info.is_dir():
                    source = source + '/'
                    target = target + '/'
                trans_iter = tview.add_to_queue(
                    direction, source, target, info.size,
                    None, remote_view.site_info, trans_iter)
            iter = self.__model.iter_next(iter)
        return
        
    def filelist_sort(self, treemodel, iter1, iter2, *arg):
        sort_folder_on_top = config_value(self.__config, 'display',
                                          'sort_folder_on_top')
        col, order = treemodel.get_sort_column_id()
        if order == SORT_ASCENDING:
            parent_weight = 1
            if sort_folder_on_top:
                dir_weight = 2
            else:
                dir_weight = 3
            file_weight = 3
        else:
            parent_weight = 3
            if sort_folder_on_top:
                dir_weight = 2
            else:
                dir_weight = 1
            file_weight = 1

        item1 = treemodel.get_value(iter1, LocalView.COL_INFO)
        item2 = treemodel.get_value(iter2, LocalView.COL_INFO)

        if col == LocalView.COL_FILENAME:
            weight1 = item1.name
        elif col == LocalView.COL_FILESIZE:
            weight1 = item1.size
        elif col == LocalView.COL_FILETYPE:
            weight1 = treemodel.get_value(iter1, LocalView.COL_FILETYPE)
        elif col == LocalView.COL_FILEMTIME:
            weight1 = item1.mtime
            
        if item1.name == '..':
            weight1 = (parent_weight, weight1)
        elif item1.is_dir():
            weight1 = (dir_weight, weight1)
        else:
            weight1 = (file_weight, weight1)
            
        if col == LocalView.COL_FILENAME:
            weight2 = item2.name
        elif col == LocalView.COL_FILESIZE:
            weight2 = item2.size
        elif col == LocalView.COL_FILETYPE:
            weight2 = treemodel.get_value(iter2, LocalView.COL_FILETYPE)
        elif col == LocalView.COL_FILEMTIME:
            weight2 = item2.mtime
            
        if item2.name == '..':
            weight2 = (parent_weight, weight2)
        elif item2.is_dir():
            weight2 = (dir_weight, weight2)
        else:
            weight2 = (file_weight, weight2)
            
        if weight1 > weight2:
            return 1
        elif weight1 < weight2:
            return -1
        else:
            return 0

    def on_updir_action_update(self, obj):
        obj.set_property('sensitive', self.__current_path != '/')
        return

    def on_updir_action_execute(self, obj, *args):
        """Enter the parent directory of the current directory. If current
        directory is root, do nothing."""
        pos = self.__current_path.rindex(u'/')
        if pos == 0:
            pos = 1
        self.set_path(self.__current_path[:pos])
        return

    def on_queue_action_execute(self, obj, *args):
        self.__list.get_selection().selected_foreach(self.add_to_queue, None)
        return

    def on_transfer_queue_action_update(self, obj, *args):
        if self.__selected_count > 0:
            another_view = self.__main_window.get_another_view(self)
            obj.set_property('sensitive', another_view.is_ready())
        else:
            obj.set_property('sensitive', False)
        return
    
    def on_transfer_action_execute(self, obj, *args):
        self.on_queue_action_execute(obj, *args)
        self.__main_window.transfer_view.start_transfer(obj, *args)
        return

    def on_transfer_queue_as_action_update(self, obj, *args):
        if self.__selected_count == 1:
            another_view = self.__main_window.get_another_view(self)
            obj.set_property('sensitive', another_view.is_ready())
        else:
            obj.set_property('sensitive', False)
        return

    def on_transfer_as_action_execute(self, obj, *args):
        def on_dialog_response(dlg, resp, *args):
            v = utf8_to_unicode(string.strip(dlg.value))
            dlg.destroy()
            if resp == RESPONSE_OK and v != '':
                self.__list.get_selection().selected_foreach(
                    self.add_to_queue, v)
                self.__main_window.transfer_view.start_transfer(obj, None)
            return
        
        if len(self.__selections) != 1: return
        iter = self.__selections[0]
        info = self.__model.get_value(iter, LocalView.COL_INFO)
        d = GeneralInputDialog(_("Transfer As"), _("Name"), info.name)
        d.connect('response', on_dialog_response)
        resp = d.run()
        return
    
    def on_queue_as_action_execute(self, obj, *args):
        def on_dialog_response(dlg, resp, *args):
            v = utf8_to_unicode(string.strip(dlg.value))
            dlg.destroy()
            if resp == RESPONSE_OK and v != '':
                self.__list.get_selection().selected_foreach(
                    self.add_to_queue, v)
            return
        if len(self.__selections) != 1: return
        iter = self.__selections[0]
        info = self.__model.get_value(iter, LocalView.COL_INFO)
        d = GeneralInputDialog(_("Queue As"), _("Name"), info.name)
        d.connect('response', on_dialog_response)
        resp = d.run()
        return

    def on_delete_action_update(self, obj, *args):
        obj.set_property('sensitive', self.__selected_count > 0)
        return
    
    def on_delete_action_execute(self, obj, *args):
        def on_dialog_response(dlg, resp, *args):
            def delete_each(treemodel, path, iter):
                name = self.__model.get_value(iter, LocalView.COL_FILENAME)
                top = os.path.join(self.__current_path, name)
                if os.path.isdir(top):
                    for root, dirs, files in os.walk(top, topdown=False):
                        for name in files:
                            os.remove(os.path.join(root, name))
                        for name in dirs:
                            os.rmdir(os.path.join(root, name))
                    os.rmdir(top)
                else:
                    os.remove(top)
                return

            dlg.destroy()
            if resp == RESPONSE_YES:
               self.__list.get_selection().selected_foreach(delete_each)
               self.refresh()
            return

        dlg = MessageDialog(flags=DIALOG_MODAL,
                            type=MESSAGE_QUESTION,
                            buttons=BUTTONS_YES_NO,
                            message_format=_("Are you sure?"))
        dlg.connect('response', on_dialog_response)
        dlg.show()
        dlg.set_modal(True)
        return

    def on_rename_action_update(self, obj, *args):
        obj.set_property('sensitive', self.__selected_count == 1)
        return

    def on_rename_action_execute(self, obj, *args):
        def on_dialog_response(dlg, resp, *args):
            v = string.strip(dlg.value)
            dlg.destroy()
            if resp == RESPONSE_OK and v != filename:
                src = os.path.join(self.__current_path, filename)
                dst = os.path.join(self.__current_path, utf8_to_unicode(v))
                try:
                    os.rename(src, dst)
                    if os.path.dirname(src) == os.path.dirname(dst):
                        self.__model.set_value(iter, LocalView.COL_FILENAME, v)
                    else:
                        self.__model.remove(iter)
                except OSError, (errno, errmsg):
                    show_error_message(errmsg)
            return

        if len(self.__selections) != 1:
            return
        
        iter = self.__selections[0]
        filename = self.__model.get_value(iter, LocalView.COL_FILENAME)
        
        from general_input import GeneralInputDialog
        dlg = GeneralInputDialog(_("Rename"),
                                 _("Please input new name:"), filename)
        dlg.connect('response', on_dialog_response)
        dlg.run()
        return

    def on_refresh_action_execute(self, obj, *args):
        self.refresh()

    def on_mkdir_action_execute(self, obj, *args):
        def on_dialog_response(dlg, resp, *args):
            v = utf8_to_unicode(string.strip(dlg.value))
            dlg.destroy()
            if resp == RESPONSE_OK and len(v) > 0:
                path = os.path.join(self.__current_path, v)
                try:
                    os.mkdir(path)
                    self.refresh()
                except OSError, (errno, errmsg):
                    show_error_message(errmsg)
            return

        from general_input import GeneralInputDialog
        dlg = GeneralInputDialog(_("Make Folder"),
                                 _("Please input folder name:"), '')
        dlg.connect('response', on_dialog_response)
        resp = dlg.run()
        return

    def on_chdir_action_execute(self, obj, *args):
        def on_dialog_response(dlg, resp, *args):
            v = utf8_to_unicode(string.strip(dlg.value))
            dlg.destroy()
            if resp == RESPONSE_OK and len(v) > 0:
                orig = self.__current_path
                try:
                    self.set_path(v)
                except OSError, (errno, errmsg):
                    show_error_message(errmsg)
                    self.set_path(orig)

        from general_input import GeneralInputDialog
        dlg = GeneralInputDialog(_("Change Folder"),
                                 _("Please input folder name:"),
                                 self.__current_path)
        dlg.connect('response', on_dialog_response)
        resp = dlg.run()
        return

    def on_sort_action_execute(self, action, widget, *args):
        if self.__change_sort_menu_item:
            self.__change_sort_menu_item = False

            column, order = self.__model.get_sort_column_id()
            widget_name = widget.get_name()
            if widget_name == 'mi_local_arr_by_name':
                column = LocalView.COL_FILENAME
            elif widget_name == 'mi_local_arr_by_type':
                column = LocalView.COL_FILETYPE
            elif widget_name == 'mi_local_arr_by_size':
                column = LocalView.COL_FILESIZE
            elif widget_name == 'mi_local_arr_by_date':
                column = LocalView.COL_FILEMTIME
            elif widget_name == 'mi_local_arr_ascending':
                order = SORT_ASCENDING
            elif widget_name == 'mi_local_arr_descending':
                order = SORT_DESCENDING
            else:
                raise ValueError, widget_name

            self.__model.set_sort_column_id(column, order)
            
            self.__change_sort_menu_item = True
        return

    def on_list_sort_column_changed(self, obj, *args):
        if self.__change_sort_menu_item:
            self.__change_sort_menu_item = False
            
            column, order = obj.get_sort_column_id()
            if column == LocalView.COL_FILENAME:
                widget_name = 'mi_local_arr_by_name'
            elif column == LocalView.COL_FILETYPE:
                widget_name = 'mi_local_arr_by_type'
            elif column == LocalView.COL_FILESIZE:
                widget_name = 'mi_local_arr_by_size'
            elif column == LocalView.COL_FILEMTIME:
                widget_name = 'mi_local_arr_by_date'
            widget = self.__menu_xml.get_widget(widget_name)
            widget.set_active(True)
            if order == SORT_ASCENDING:
                widget_name = 'mi_local_arr_ascending'
            elif order == SORT_DESCENDING:
                widget_name = 'mi_local_arr_descending'
            widget = self.__menu_xml.get_widget(widget_name)
            widget.set_active(True)
            
            self.__change_sort_menu_item = True            
        return

    def on_open_action_update(self, obj, *args):
        obj.set_property('sensitive', self.__selected_count == 1)
        return

    def on_open_action_execute(self, obj, *args):
        if len(self.__selections) != 1:
            return

        iter = self.__selections[0]
        info = self.__model.get_value(iter, LocalView.COL_INFO)
        if info.is_dir():
            return
        fullpath = os.path.join(self.__current_path, info.name)
        get_filetype(fullpath).open()
        return
    
    def on_local_dir_entry_activate(self, obj, *args):
        new_path = self.__cmb_dir.child.get_text()
        if os.path.isdir(new_path):
            self.set_path(new_path)
        else:
            dlg = MessageDialog(flags=DIALOG_MODAL,
                                type=MESSAGE_ERROR,
                                buttons=BUTTONS_OK,
                                message_format=_("Directory %s not found.") % new_path)
            dlg.connect('response', lambda obj, *args: obj.destroy())
            dlg.show()
            dlg.set_modal(True)
        return
    
    def is_ready(self):
        return True

    def on_auto_size_file_list_columns_change(self, config, id, value, *args):
        for column in self.__list.get_columns():
            if value.get_bool():
                column.set_sizing(TREE_VIEW_COLUMN_AUTOSIZE)
            else:
                column.set_sizing(TREE_VIEW_COLUMN_GROW_ONLY)
        return

    def on_use_custom_file_listing_font_change(self, config, id, value, *args):
        self.__use_custom_file_listing_font = value.get_bool()
        self.__change_font()
        return

    def on_file_listing_font_change(self, config, id, value, *args):
        self.__file_listing_font = value.get_string()
        self.__change_font()
        return

    def __change_font(self):
        for renderer in self.__text_renderers:
            if self.__use_custom_file_listing_font:
                renderer.set_property('font', self.__file_listing_font)
            else:
                renderer.set_property('font', None)
        return

    def on_show_hidden_execute(self, *args):
        self.__show_hidden = not self.__show_hidden
        self.refresh()
